/* ****************************************************************************
 *
 * Copyright (c) Microsoft Corporation. 
 *
 * This source code is subject to terms and conditions of the Microsoft Public License. A 
 * copy of the license can be found in the License.html file at the root of this distribution. If 
 * you cannot locate the  Microsoft Public License, please send an email to 
 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
 * by the terms of the Microsoft Public License.
 *
 * You must not remove this notice, or any other, from this software.
 *
 * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
 * PARTICULAR PURPOSE.
 * ***************************************************************************/


#include "stdafx.h"
#include <pgl/core/pgl.h>
#include <pgl/core/PGLArchive.h>
#include <pgl/core/PGLRegion.h>
#include <pgl/core/PGLDef.h>
#include <pgl/core/PGLCoreGlobal.h>
#include <pgl/igfx/EPSInterface.h>
#include <pgl/igfx/SVGInterface.h>

#ifdef _PGL_USE_ZIPARCHIVE

#endif

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif


#ifdef _PGL_SHAREWARE
	#define PGL_DRAW_OVERLAY( gfx) \
	m_sTextOverlay=_T("Generated by Plot Grapic Library Shareware");\
	if (!m_sTextOverlay.IsEmpty())\
	{\
		gfx.SetColor(0,0,0);\
		gfx.SetFont(m_lfTextOverlay);\
		gfx.DrawText(0,0, m_sTextOverlay);\
	}
#else
	#define PGL_DRAW_OVERLAY( gfx) \
	if (!m_sTextOverlay.IsEmpty())\
	{\
		gfx.SetColor(0,0,0);\
		gfx.SetFont(m_lfTextOverlay);\
		gfx.DrawText(0,0, m_sTextOverlay);\
	}
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CPGLArchive::CPGLArchive(CPGLRegionStPtr pRegion, gfxinterface::CGfxInterface* pGfxInterface)
: 
m_pRegion(pRegion), 
m_pGfxInterface(pGfxInterface), 
m_sTextOverlay(_T("Generated by Plot Graphic Library.")),
m_eJPEGTransform( JPEGTransformNone), 
m_lJPEGQuality( 75 ),
m_eTIFFCompression( TIFFCompressionNone ), 
m_eTIFFColorDepth( TIFFColorDepth24 ),
m_bZipping(false),
m_eRenderOption(0)
{
	using namespace markup;
	m_pXml = new CMarkupArchive;

	m_lfTextOverlay.lfHeight=6;
	m_lfTextOverlay.lfWidth=0;
	m_lfTextOverlay.lfEscapement=0;
	m_lfTextOverlay.lfOrientation=0;
	m_lfTextOverlay.lfWeight=FW_NORMAL;
	m_lfTextOverlay.lfItalic=FALSE;
	m_lfTextOverlay.lfUnderline=FALSE;
	m_lfTextOverlay.lfStrikeOut=FALSE;
	m_lfTextOverlay.lfCharSet=ANSI_CHARSET;
	m_lfTextOverlay.lfOutPrecision=OUT_TT_PRECIS;
	m_lfTextOverlay.lfClipPrecision=CLIP_DEFAULT_PRECIS;
	m_lfTextOverlay.lfQuality=ANTIALIASED_QUALITY;
	m_lfTextOverlay.lfPitchAndFamily=FF_DONTCARE|DEFAULT_PITCH;
	_tcscpy(m_lfTextOverlay.lfFaceName,_T("Verdana"));
}

CPGLArchive::CPGLArchive(CPGLRegionStPtr pRegion, CArchive& ar, gfxinterface::CGfxInterface* pGfxInterface)
: 
m_pRegion(pRegion), 
m_pGfxInterface(pGfxInterface), 
m_sTextOverlay(_T("Generated by Plot Graphic Library.")), 
m_eJPEGTransform( JPEGTransformNone), 
m_lJPEGQuality( 75 ),
m_eTIFFCompression( TIFFCompressionNone ), 
m_eTIFFColorDepth( TIFFColorDepth24 ),
m_bZipping(false),
m_eRenderOption(0)
{
	using namespace markup;
	m_pXml = new CMarkupArchive;

	m_lfTextOverlay.lfHeight=6;
	m_lfTextOverlay.lfWidth=0;
	m_lfTextOverlay.lfEscapement=0;
	m_lfTextOverlay.lfOrientation=0;
	m_lfTextOverlay.lfWeight=FW_NORMAL;
	m_lfTextOverlay.lfItalic=FALSE;
	m_lfTextOverlay.lfUnderline=FALSE;
	m_lfTextOverlay.lfStrikeOut=FALSE;
	m_lfTextOverlay.lfCharSet=ANSI_CHARSET;
	m_lfTextOverlay.lfOutPrecision=OUT_TT_PRECIS;
	m_lfTextOverlay.lfClipPrecision=CLIP_DEFAULT_PRECIS;
	m_lfTextOverlay.lfQuality=ANTIALIASED_QUALITY;
	m_lfTextOverlay.lfPitchAndFamily=FF_DONTCARE|DEFAULT_PITCH;
	_tcscpy(m_lfTextOverlay.lfFaceName,_T("Verdana"));

	if (!m_pRegion)
		return;

	CString str;
	if (ar.IsStoring())
	{
		SaveString(str);
		ar<<str;
	}
	else
	{
		ASSERT(m_pRegion);
		ar>>str;
		LoadString(str);
	}
}


CPGLArchive::~CPGLArchive()
{
	using namespace markup;

	m_pRegion.reset();

	if (m_pXml)
		delete (CMarkupArchive*)m_pXml;
}

bool CPGLArchive::Load(LPCTSTR szFileName)
{
	using namespace markup;
	ASSERT(m_pXml);
	CMarkupArchive& xml = *((CMarkupArchive*)m_pXml);
	
	if (!m_pRegion)
		return false;


	m_bStoring=false;
	if ( xml.LoadFile(szFileName) )
	{
		if ( xml.FindElem(_T("pgl")))
		{
			SerializeGfx();
			m_pRegion->SerializeXML(*this);
			return true;
		}
		else
			return false;
	}
	else 
		return false;
}

bool CPGLArchive::Save(LPCTSTR szFileName)
{
	using namespace markup;
	ASSERT(m_pXml);
	CMarkupArchive& xml = *((CMarkupArchive*)m_pXml);

	if (!m_pRegion)
		return false;

	m_bStoring=true;
	xml.AddElem(_T("pgl"));
	SerializeGfx();
	m_pRegion->SerializeXML(*this);

	xml.SetZipping( m_bZipping);
	return 	xml.SaveFile(szFileName);
}

bool CPGLArchive::LoadString(LPCTSTR szXMLString)
{
	using namespace markup;
	using namespace gfxinterface;

	ASSERT(m_pXml);
	CMarkupArchive& xml = *((CMarkupArchive*)m_pXml);

	if (!m_pRegion)
		return false;

	m_bStoring=false;
	if ( xml.LoadString(szXMLString) )
	{
		if ( xml.FindElem(_T("pgl")))
		{
			SerializeGfx();			

			m_pRegion->SerializeXML(*this);
			return true;
		}
		else
			return false;
	}
	else 
		return false;
}

bool CPGLArchive::SaveString(CString& sXMLString)
{
	using namespace markup;
	using namespace gfxinterface;

	if (!m_pRegion)
		return false;

	ASSERT(m_pXml);
	CMarkupArchive& xml = *((CMarkupArchive*)m_pXml);

	m_bStoring=true;
		
	xml.AddElem(_T("pgl"));
	SerializeGfx();
	// serializing region
	m_pRegion->SerializeXML(*this);
	sXMLString=xml.GetDoc();

	return true;
}

void CPGLArchive::Serialize( CArchive& ar)
{
	if (!m_pRegion)
		return;

	CString str;
	if (ar.IsStoring())
	{
		SaveString(str);
		ar<<str;
	}
	else
	{
		ASSERT(m_pRegion);
		ar>>str;
		LoadString(str);
	}
}


bool CPGLArchive::ExportToFile(
    EFileFormat eFileFormat, 
    LPCTSTR szFile, 
    const CPGLPointU &dim, 
    HDC hDC, 
    bool bZoomAll)
{
	using namespace gfxinterface;
	using namespace Gdiplus;
	USES_CONVERSION;

	if (!m_pRegion || __min(dim.x,dim.y)==0)
		return false;

	// getting extension...
	CString sFN = szFile;
	CString sExtension = sFN.Right( sFN.GetLength() - sFN.ReverseFind('.') -1);
	if (sExtension==sFN)
		sExtension=_T("");
	sExtension.MakeLower();

	// making sure extension is right...
	CPGLArchive::ProcessFileNameExt(sFN, sExtension, eFileFormat);

	// Creation date
	CString szCreationDate = CTime::GetCurrentTime().Format( _T("%A, %B %d, %Y") );

	// eps output
	if (eFileFormat == FileFormatEPS)
	{
		CEPSInterface eps;
		eps.SetCreator(m_sCreator);
		eps.SetTitle(m_sTitle);
		eps.SetMainBoundingBox(0, 0, dim.x, dim.y);
			
		m_pRegion->SetViewport(0, 0 , dim.x, dim.y);

		eps.BeginPaint(hDC);
			if (bZoomAll)
				m_pRegion->ZoomAll(eps,true);
			else
				m_pRegion->RefreshView(eps,true);
			m_pRegion->PlotGfx(eps);
			PGL_DRAW_OVERLAY(eps);
			eps.EndPaint();
		eps.EndPaint();

		return eps.Save(sFN);
	}

	// svg output
	if (eFileFormat == FileFormatSVG || eFileFormat == FileFormatSVGZ)
	{ 
		CSVGInterface svg;

		svg.SetCreator(m_sCreator);
		svg.SetTitle(m_sTitle);
		svg.SetMainBoundingBox(0, 0, dim.x, dim.y);
		m_pRegion->SetViewport(0, 0 , dim.x, dim.y);
		svg.BeginPaint(hDC);
			if (bZoomAll)
				m_pRegion->ZoomAll(svg,true);
			else
				m_pRegion->RefreshView(svg,true);
			m_pRegion->PlotGfx(svg);
			PGL_DRAW_OVERLAY(svg);
			svg.EndPaint();

		if (eFileFormat == FileFormatSVGZ)
			svg.SetOutputType(CSVGInterface::OutputSVGZ);
		return svg.Save(sFN, eFileFormat == FileFormatSVGZ);
	}

	// metafile output
	if (eFileFormat == FileFormatEMFOnly
		|| eFileFormat == FileFormatEMFPlusOnly
		|| eFileFormat == FileFormatEMFPlusDual)
	{

		Rect rect(0,0,dim.x,dim.y);
		
		bool bDeleteHDC = false;
		bool bSuccess;
		if (hDC == NULL)
		{
			hDC = ::CreateDC( _T("DISPLAY"), NULL, NULL, NULL);
			bDeleteHDC=true;
			if (hDC==NULL)
				return false;
		}

	#ifdef _UNICODE
		Metafile metafile(sFN, hDC, rect,  MetafileFrameUnitPixel); 
	#else
		Metafile metafile(A2CW( sFN ), hDC, rect,  MetafileFrameUnitPixel); 
	#endif
		{
			bSuccess=ExportToMetafile(&metafile, dim, hDC, bZoomAll);
		}
	
		if (bDeleteHDC)
			VERIFY(::DeleteDC( hDC ) );

		return bSuccess;
	}	


	CLSID Clsid;
	WCHAR codec[20];

	if (eFileFormat == FileFormatJPG)
		wcsncpy(codec,L"image/jpeg\0",11);
	else if (eFileFormat == FileFormatPNG)
		wcsncpy(codec,L"image/png\0",10);
	else if (eFileFormat == FileFormatTIFF)
		wcsncpy(codec,L"image/tiff\0",11);
	else if (eFileFormat == FileFormatBMP)
		wcsncpy(codec,L"image/bmp\0",10);
	else
	{
		return false;
	}
	
	if (CGDIpHelper::GetEncoderClsid(codec, &Clsid)<0)
	{
		return false;
	}
	
	
	Bitmap image(dim.x, dim.y, PixelFormat32bppARGB );

	VERIFY(ExportToImage(&image, hDC, bZoomAll));

	VERIFY(image.GetLastStatus() == Ok);

	EncoderParameters* pEncoderParameters=GetEncoderParameters( eFileFormat);

#ifdef _UNICODE
	if (pEncoderParameters)
	{
		image.Save(sFN, &Clsid, pEncoderParameters);
		free(pEncoderParameters);
	}
	else
		image.Save(sFN, &Clsid);
#else
	if (pEncoderParameters)
	{
		image.Save(A2CW( sFN ), &Clsid, pEncoderParameters);
		free(pEncoderParameters);
	}
	else
		image.Save(A2CW( sFN ), &Clsid);
#endif
	return (image.GetLastStatus() == Ok);
}

bool CPGLArchive::ExportToStream( 
    EFileFormat eFileFormat, 
    IStream* pIStream, 
    const CPGLPointU& dim, 
    HDC hDC, 
    bool bZoomAll
    )
{
	using namespace Gdiplus;
	using namespace gfxinterface;
	USES_CONVERSION;

	if (!m_pRegion || __min(dim.x,dim.y)==0 || !pIStream)
		return false;

	CLSID Clsid;

	// EPS And SVG
	switch (eFileFormat)
	{
	case FileFormatEPS:
	case FileFormatSVG:
		return false;
	}

	// EMF and WMF
	switch(eFileFormat)
	{
	case FileFormatEMFOnly:
	case FileFormatEMFPlusOnly:
	case FileFormatEMFPlusDual:
		return ExportMetafileToStream(eFileFormat, pIStream, dim, hDC, bZoomAll);
	}

	LPWSTR szCodec;
	switch(eFileFormat)
	{
	case FileFormatJPG:
		szCodec=A2BSTR("image/jpeg");
		break;
	case FileFormatTIFF:
		szCodec=A2BSTR("image/tiff");
		break;
	case FileFormatBMP:
		szCodec=A2BSTR("image/bmp");
		break;
	default:
		szCodec=A2BSTR("image/png");
	}
	
	if (CGDIpHelper::GetEncoderClsid(szCodec, &Clsid)<0)
		return false;
	
	Bitmap image(dim.x, dim.y, PixelFormat32bppARGB );

	VERIFY(ExportToImage(&image, hDC, bZoomAll));			

	VERIFY(image.GetLastStatus() == Ok);


	EncoderParameters* pEncoderParameters=GetEncoderParameters( eFileFormat);

	if (pEncoderParameters)
	{
		image.Save(pIStream, &Clsid, pEncoderParameters);
		free(pEncoderParameters);
	}
	else
		image.Save(pIStream, &Clsid);

	return (image.GetLastStatus() == Ok);
}

bool CPGLArchive::ExportMetafileToStream( 
    EFileFormat eFileFormat, 
    IStream* pIStream, 
    const CPGLPointU& dim, 
    HDC hDC, 
    bool bZoomAll
    )
{
	using namespace Gdiplus;

	if (eFileFormat != FileFormatEMFOnly 
		&& eFileFormat != FileFormatEMFPlusOnly
		&& eFileFormat != FileFormatEMFPlusDual)
		return false;
	if (!pIStream)
		return false;

	Rect rect(0,0,dim.x,dim.y);

	// creating dc if needed
	bool bDeleteHDC = false;
	if (hDC == NULL)
	{
		hDC = ::CreateDC( _T("DISPLAY"), NULL, NULL, NULL);
		bDeleteHDC=true;
		if (hDC==NULL)
			return false;
	}

	bool bSuccess;
	EmfType eType;
	switch(eFileFormat)
	{
	case FileFormatEMFOnly:
		eType=EmfTypeEmfOnly;
		break;
	case FileFormatEMFPlusOnly:
		eType=EmfTypeEmfPlusOnly;
		break;
	default:
		eType=EmfTypeEmfPlusDual;
	}

	Metafile metafile(pIStream, hDC, rect,  MetafileFrameUnitPixel, eType);
	{
		bSuccess=ExportToMetafile(&metafile, dim, hDC, bZoomAll);			
	}

	if (bDeleteHDC)
		VERIFY(::DeleteDC( hDC ) );

	return bSuccess;
}

bool CPGLArchive::ExportToMetafile(
    Gdiplus::Metafile* pMeta, 
    const CPGLPointU& dim, 
    HDC hDC, 
    bool bZoomAll
    )
{
	using namespace Gdiplus;
	using namespace gfxinterface;
	bool bDeleteDC = false;

	if (!pMeta || pMeta->GetLastStatus()!=Ok)
		return false;

	ASSERT(pMeta->GetLastStatus() == Ok);
	Graphics graphics(pMeta);
	ASSERT(graphics.GetLastStatus() == Ok);

	CGDIpInterface gdip;
    gdip.SetRenderOption(m_eRenderOption);
	gdip.SetGraphics(&graphics);
	gdip.SetMainBoundingBox(0, 0, dim.x,dim.y);
	m_pRegion->SetViewport(0, 0 , dim.x,dim.y);

	if (hDC == NULL)
	{
		hDC = ::CreateDC(_T("DISPLAY"),NULL,NULL,NULL);
		ASSERT(hDC);
		bDeleteDC = true;
	}

	gdip.BeginPaint(hDC);
		if (bZoomAll)
			m_pRegion->ZoomAll(gdip,true);
		else
			m_pRegion->RefreshView(gdip,true);
		m_pRegion->PlotGfx(gdip);
		PGL_DRAW_OVERLAY(gdip);
	gdip.EndPaint();			
	
	if (bDeleteDC)
		VERIFY(::DeleteDC(hDC));

	return (pMeta->GetLastStatus() == Ok);
}

bool CPGLArchive::ExportToImage(
    Gdiplus::Image* pImage, 
    HDC hDC, 
    bool bZoomAll)
{
	using namespace Gdiplus;
	using namespace gfxinterface;
	bool bDeleteDC = false;

	if (!pImage || pImage->GetLastStatus()!=Ok)
		return false;

	{
		ASSERT(pImage->GetLastStatus() == Ok);
		boost::scoped_ptr<Graphics> pGraphics( Graphics::FromImage(pImage) );
		ASSERT(pGraphics->GetLastStatus() == Ok);

		CGDIpInterface gdip;
        gdip.SetRenderOption(m_eRenderOption);
		gdip.SetGraphics(pGraphics.get());
		gdip.SetMainBoundingBox(
			0, 0, 
			pImage->GetWidth(), pImage->GetHeight()
			);
		m_pRegion->SetViewport(
			0, 0 , 
			pImage->GetWidth(), pImage->GetHeight()
			);

		if (hDC == NULL)
		{
			hDC = ::CreateDC(_T("DISPLAY"),NULL,NULL,NULL);
			ASSERT(hDC);
			bDeleteDC = true;
		}

		gdip.BeginPaint(hDC);
			if (bZoomAll)
				m_pRegion->ZoomAll(gdip,true);
			else
				m_pRegion->RefreshView(gdip,true);
			m_pRegion->PlotGfx(gdip);
			PGL_DRAW_OVERLAY(gdip);
		gdip.EndPaint();			
	}

	if (bDeleteDC)
		VERIFY(::DeleteDC(hDC));

	return (pImage->GetLastStatus() == Ok);
}

bool CPGLArchive::ExportToBitmap(
		  size_t width_,
		  size_t height_,
		  size_t stride_,
		  size_t bpp_,
		  unsigned char* bits_,
		  HDC hDC, 
		  bool bZoomAll
		  )
{
	using namespace Gdiplus;
	using namespace gfxinterface;

	if (
		!width_
		|| !height_
		|| !bpp_
		|| !stride_
		|| !bits_)
		return false;

	// creating bitmap...
	PixelFormat pf;
	switch(bpp_)
	{
	case 8:
		pf=PixelFormat8bppIndexed; break;
	case 16:
		pf=PixelFormat16bppRGB555; break;
	case 32:
		pf=PixelFormat32bppARGB; break;
	case 24:
		pf=PixelFormat24bppRGB;break;
	default:
		return false;
	}
#ifdef _DEBUG
#undef new
#endif
	boost::scoped_ptr<Bitmap> bmp(
		new Bitmap(
		width_,
		height_,
		stride_,
		pf,
		bits_
		)
		);
#ifdef _DEBUG
#define new DEBUG_NEW
#endif

	return ExportToImage(bmp.get(),hDC,bZoomAll);
};

bool CPGLArchive::ExportToString( 
    EFileFormat eFileFormat, 
    CString& string, 
    const CPGLPointU& dim, 
    bool bZoomAll, 
    HDC hDC)
{
	using namespace gfxinterface;

	if (__min(dim.x,dim.y)==0)
		return false;

	bool bDeleteDC=false;
	CFileGfxInterface* pGfx=NULL;

	switch(eFileFormat)
	{
	case FileFormatEPS:
		pGfx=new CEPSInterface;
		break;
	case FileFormatSVG:
		pGfx=new CSVGInterface;
		break;
	default:
		return false;
	}

	if (!hDC)
	{
		hDC = ::CreateDC( _T("DISPLAY"),NULL,NULL,NULL);
		bDeleteDC = true;
	}
	if (!hDC)
		goto Cleaning;

    pGfx->SetRenderOption(m_eRenderOption);
	pGfx->SetMainBoundingBox(0, 0, dim.x, dim.y);			
		
	m_pRegion->SetViewport(0, 0 , dim.x, dim.y);
	pGfx->BeginPaint(hDC);
		if (bZoomAll)
			m_pRegion->ZoomAll(*pGfx,true);
		else
			m_pRegion->RefreshView(*pGfx,true);
		m_pRegion->PlotGfx(*pGfx);
		PGL_DRAW_OVERLAY((*pGfx));
	pGfx->EndPaint();

	pGfx->GetString(string);

	// if

Cleaning:
	if (pGfx)
		delete pGfx;
	if (hDC && bDeleteDC)
		::DeleteDC(hDC);

	return true;
}


bool CPGLArchive::ExportToClipBoard( 
    EClipBoardType eClipBoardType, 
    bool bZoomAll, 
    const CPGLPointU& dim, 
    HWND hWnd
    )
{
	using namespace Gdiplus;
	using namespace gfxinterface;

	if (!m_pRegion)
		return false;

	if (dim.x==0 || dim.y==0)
		return false;

	if ( !::OpenClipboard(hWnd) )
		return false;

	// Remove the current Clipboard contents
	if( !::EmptyClipboard() )
		return false;

	m_pRegion->SetViewport(0,0,dim.x,dim.y);

	CGDIpInterface gfx;
    gfx.SetRenderOption(m_eRenderOption);
	gfx.SetMainBoundingBox(0,0,dim.x, dim.y);
	HANDLE hResult;
	HENHMETAFILE hEnhMetaFile;
	Rect rect;

	HDC hDC;
	if (hWnd)
	{
		hDC = ::GetDC(hWnd);
		if (!hDC)
			return false;
	}
	else
	{
		hDC = ::CreateDC( _T("DISPLAY"),NULL,NULL,NULL);
	}

	switch(eClipBoardType)
	{
	case ClipBoardMetafile:
		rect.X=rect.Y=0;
		rect.Width=dim.x;
		rect.Height=dim.y;
		{
			Metafile metafile(hDC, rect, MetafileFrameUnitPixel); 
			{
				Graphics graphics(&metafile);
				gfx.SetGraphics(&graphics);
				gfx.BeginPaint(hDC);
					if (bZoomAll)
						m_pRegion->ZoomAll(gfx,true);
					else
						m_pRegion->RefreshView(gfx,true);
					m_pRegion->PlotGfx(gfx);
				PGL_DRAW_OVERLAY(gfx);
				gfx.EndPaint();		
			}
	
			hEnhMetaFile=metafile.GetHENHMETAFILE();
	
			hResult = ::SetClipboardData(CF_ENHMETAFILE,hEnhMetaFile);
			if (!hResult)
			{
				if (hWnd)
					::ReleaseDC(hWnd, hDC);
				else
					::DeleteDC(hDC);

				return false;
			}
		}
		break;

	case ClipBoardBitmap:
		Bitmap bitmap(dim.x, dim.y);

		ExportToImage(&bitmap, hDC, bZoomAll);

		// creating memory dc and bitmap, attaching bitmap to dc
		HDC hBitmapDC = ::CreateCompatibleDC(hDC);
		if (!hBitmapDC)
			return false;
		HBITMAP hBitmapDetach =::CreateCompatibleBitmap(hDC, dim.x, dim.y);
		if (!hBitmapDetach)
			return false;

		HANDLE oldBitmapHandle=::SelectObject(hBitmapDC, hBitmapDetach);

		// draw bitmap to hDC,
		{
			Graphics graphics(hBitmapDC);
			graphics.DrawImage(&bitmap,Point(0,0));
		}

		// detaching handles
		::SelectObject(hBitmapDC, oldBitmapHandle);
		
		// delete memory dc
		::DeleteDC(hBitmapDC);

		hResult = ::SetClipboardData(CF_BITMAP,hBitmapDetach);
		if (!hResult)
		{
			if (hWnd)
				::ReleaseDC(hWnd, hDC);
			else
				::DeleteDC(hDC);
			return false;
		}

		break;		
	}
	
	if (hWnd)
		::ReleaseDC(hWnd, hDC);
	else
		::DeleteDC(hDC);

	return ::CloseClipboard();
}

DWORD CPGLArchive::GetRenderOption() const
{
    return m_eRenderOption;
}
void CPGLArchive::SetRenderOption(DWORD eo_)
{
    m_eRenderOption = eo_;
}

CString CPGLArchive::GetFileDialogFilter()
{
	CString szFilter = _T("PNG, Portable Network Graphics (*.png)|*.png|");
	szFilter+=_T("JPEG (*.jpg,*.jpeg)|*.jpg;*.jpeg|");
	szFilter+=_T("TIFF, Tagged-image file format (*.tiff)|*.tiff|");
	szFilter+=_T("BMP, Windows Bitmap (*.bmp)|*.bmp|");
	szFilter+=_T("EMF,WMF, GDI Windows Metafile (*.emf)|*.emf|");
	szFilter+=_T("EMF+, GDI+ Enhanced Windows Metafile (*.emf)|*.emf|");
	szFilter+=_T("EMF dual, GDI-GDI+ Enhanced Windows Metafile (*.emf)|*.emf|");
	szFilter+=_T("EPS, Encapsulated Postscript (*.eps)|*.eps|");
	szFilter+=_T("SVG, Scalable Vector Graphics (*.svg)|*.svg|");
	szFilter+=_T("SVGZ, Scalable Vector Graphics Zipped (*.svgz)|*.svgz||");

	return szFilter;
}

void CPGLArchive::ProcessFileNameExt(
   CString &szFileName, 
   const CString& szFileExt, 
   EFileFormat eFileFormat
   )
{
	CString str=szFileExt;
	str.MakeLower();
	// getting file type...
	switch( eFileFormat )
	{
	case FileFormatPNG:
		if (str != _T("png"))
			szFileName+=_T(".png");
		break;
	case FileFormatJPG:
		if (str != _T("jpg") || str != _T("jpeg"))
			szFileName+=_T(".jpg");
		break;
	case FileFormatTIFF:
		if (str != _T("tiff"))
			szFileName+=_T(".tiff");
		break;
	case FileFormatBMP:
		if (str != _T("bmp"))
			szFileName+=_T(".bmp");
		break;
	case FileFormatEMFOnly:
	case FileFormatEMFPlusOnly:
	case FileFormatEMFPlusDual:
		if (str != _T("emf"))
			szFileName+=_T(".emf");
		break;
	case FileFormatEPS:
		if (str != _T("eps"))
			szFileName+=_T(".eps");
		break;
	case FileFormatSVG:
		if (str != _T("svg"))
			szFileName+=_T(".svg");
		break;
	case FileFormatSVGZ:
		if (str != _T("svgz"))
			szFileName+=_T(".svgz");
		break;
	}
}

void CPGLArchive::SerializeGfx()
{
	using namespace markup;
	using namespace gfxinterface;
	
	ASSERT(m_pXml);
	CMarkupArchive& xml = *((CMarkupArchive*)m_pXml);
	bool bTemp;
	DWORD dwRender;
	
	if (!m_pGfxInterface)
		return;
	
	if (m_bStoring)
	{
		xml.AddChildElem(_T("IGfx"));
		xml.IntoElem();
			xml.AddChildElem(_T("Rendering"));
			xml.IntoElem();
				xml.AddChildElemEx(_T("AntiAlias"), !(m_pGfxInterface->GetRenderOption() & CGfxInterface::RenderOptionNoAntiAlias));
				xml.AddChildElemEx(_T("TextAntiAlias"), !(m_pGfxInterface->GetRenderOption() & CGfxInterface::RenderOptionNoTextAntiAlias));
				xml.AddChildElemEx(_T("BiCubic"), !(m_pGfxInterface->GetRenderOption() & CGfxInterface::RenderOptionNoBiCubicInterpolation));
			xml.OutOfElem();
		xml.OutOfElem();
	}
	else
	{
		if( xml.FindChildElem(_T("IGfx")))
		{
			xml.IntoElem();
			if(xml.FindChildElem(_T("Rendering")))
			{
				xml.IntoElem();
				dwRender = 0;
				
				if(xml.FindGetChildData(_T("AntiAlias"), bTemp))
				{
					if (!bTemp)
						dwRender|= CGfxInterface::RenderOptionNoAntiAlias;
				}
				
				if (xml.FindGetChildData(_T("TextAntiAlias"), bTemp))
				{
					if (!bTemp)
						dwRender|= CGfxInterface::RenderOptionNoTextAntiAlias;
				}
				
				if (xml.FindGetChildData(_T("BiCubic"), bTemp))
				{
					if (!bTemp)
						dwRender|= CGfxInterface::RenderOptionNoBiCubicInterpolation;
				}
				
				m_pGfxInterface->SetRenderOption( dwRender );
				
				xml.OutOfElem();
			}
			xml.OutOfElem();
		}
	}
}

Gdiplus::EncoderParameters* 
    CPGLArchive::GetEncoderParameters(EFileFormat eFileFormat)
{
	using namespace Gdiplus;
	EncoderParameters* pEncoderParameters=NULL;

	switch( eFileFormat )
	{
	case FileFormatJPG:
		if (m_eJPEGTransform == JPEGTransformNone)
		{
			pEncoderParameters=new EncoderParameters[1];
			pEncoderParameters->Count = 1;
		}
		else
		{
			pEncoderParameters= (EncoderParameters*)malloc(sizeof(EncoderParameters) + 2 * sizeof(EncoderParameter));
			pEncoderParameters->Count = 1;
			pEncoderParameters->Parameter[1].Guid = EncoderTransformation;
			pEncoderParameters->Parameter[1].Type = EncoderParameterValueTypeLong;
			pEncoderParameters->Parameter[1].NumberOfValues = 1;
			pEncoderParameters->Parameter[1].Value = &m_eJPEGTransform;
		}

		pEncoderParameters->Parameter[0].Guid = EncoderQuality;
		pEncoderParameters->Parameter[0].Type = EncoderParameterValueTypeLong;
		pEncoderParameters->Parameter[0].NumberOfValues = 1;
		pEncoderParameters->Parameter[0].Value = &m_lJPEGQuality;

		break;

	case FileFormatTIFF:
/*
		pEncoderParameters= (EncoderParameters*)malloc(sizeof(EncoderParameters) + 2 * sizeof(EncoderParameter));
		pEncoderParameters->Count = 2;
		pEncoderParameters->Parameter[0].Guid = EncoderCompression;
		pEncoderParameters->Parameter[0].Type = EncoderParameterValueTypeLong;
		pEncoderParameters->Parameter[0].NumberOfValues = 1;
		pEncoderParameters->Parameter[0].Value = &m_eTIFFCompression;

		pEncoderParameters->Parameter[1].Guid = EncoderColorDepth;
		pEncoderParameters->Parameter[1].Type = EncoderParameterValueTypeLong;
		pEncoderParameters->Parameter[1].NumberOfValues = 1;
		pEncoderParameters->Parameter[1].Value = &m_eTIFFColorDepth;
*/
		break;

	}

	return pEncoderParameters;
};

void CPGLArchive::SetRegion(CPGLRegionStPtr pRegion)
{	
	m_pRegion=pRegion;
};

Gdiplus::Image* CPGLArchive::ImportFromStream( 
    IStream* pStream, 
    bool bTryUsingGDI
    )
{
	using namespace std;
	using namespace Gdiplus;

	HRESULT hr;
	Image* pImage=NULL;

	if (!pStream)
	{
		PGL_TRACE(_T("Invalid input stream (null pointer)\n"));
		return NULL;
	}

	if (bTryUsingGDI)
	{
		// get size of required read buffer
		// since this workaround can only deal with the stream contents
		// as an atomic buffer
        ULARGE_INTEGER pos;
        LARGE_INTEGER null64 = { 0, 0 };
        hr = pStream->Seek( null64, STREAM_SEEK_END, &pos);
        if ( FAILED(hr) ) 
		{
			PGL_TRACE(_T("Seek to stream end failed\n"));
			return NULL;
		}

        if (pos.HighPart) 
		{
			PGL_TRACE(_T("Size overflow\n"));
			return NULL;
		}
 
        // extract 32bit size (we cannot handle bigger objects here)
        size_t size = pos.LowPart;            
 
		LARGE_INTEGER displace;
		memset(&displace,0,sizeof(LARGE_INTEGER));
        hr = pStream->Seek(displace,STREAM_SEEK_SET ,NULL);
        if ( FAILED(hr) ) 
		{
			PGL_TRACE(_T("Rewind failed\n"));
			return NULL;
		}
 
        // allocate buffer and read stream contents
        BYTE* buf=new BYTE[size];
 
        hr = pStream->Read( buf, size, 0);
        if (FAILED(hr)) 
		{
			PGL_TRACE(_T("Read failed\n"));
			delete[] buf;
			return NULL;
		}
 
        // use (old) GDI function to create metafile from stream contents
        HENHMETAFILE hemf = SetEnhMetaFileBits( size, buf);
        if (!hemf)  
		{
			PGL_TRACE(_T("Setting metafile failed\n"));
		}
		else
		{
	        // now create a GDI+ object from ("old-style") GDI handle
	#ifdef _DEBUG
	#undef new
	#endif
			PGL_TRACE(_T("Loading image as Metafile\n"));
	        pImage=new Metafile(hemf, TRUE);
	#ifdef _DEBUG
	#define new DEBUG_NEW
	#endif
		}

		delete[]  buf;
	}


	// if image was not a Metafile
	if (!pImage)
	{
		PGL_TRACE(_T("Loading image as Bitmap\n"));
        // succeeds but creates bitmaps!!!
        pImage=Image::FromStream( pStream);
	}

	if (!pImage)
	{
		PGL_TRACE(_T("Broken image\n"));
		return NULL;
	}
 
    if ( pImage->GetLastStatus() != Ok )
	{
		PGL_TRACE( _T("Construction of image failed\n"));
		delete pImage;
		return NULL;
	}

	return pImage;
}
